<template>
<div :class="[$style.container]">
<el-dialog :visible.sync="visible" width="40%">
  <template v-slot:title="" v-if="sources.length > 0">
    <span v-if="sources.length > 1">已选择 {{sources.length}} 项</span>
    <span v-else>
      <doc-icon :data="sources[0]"></doc-icon>
      <span class="ml-2">{{sources[0].name}}</span>
    </span>
  </template>
  <div :class="[$style.body]">
    <div :class="[$style.menu]">
      <ul :class="[$style.list]">
        <li :class="[$style.item, spaceSelectedCls(item)]" v-for="(item, i) in renderedSpaces" :key="i" @click="onSelectSpace(item)">
          <span><svg-icon :icon="icon(item)"></svg-icon></span>
          <span class="ml-2" :title="item.name" :class="[$style.menuText]">{{item.name}}</span>
        </li>
      </ul>
    </div>
    <div :class="[$style.content]">
      <div :class="[$style.breadcrumb]">
        <div :class="[$style.navListWrap]">
          <ul :class="[$style.navList]" ref="navList">
            <li :class="[$style.navItem]" v-for="(row, i) in renderedPaths" :key="i">
              <span :class="[$style.navItemLink]" @click="onGoto(row)" v-if="!row.last">{{row.name}}</span>
              <span class="text-secondary" v-else>{{row.name}}</span>
              <span v-if="!row.last" :class="[$style.navSep]"><i class="el-icon-arrow-right"></i></span>
            </li>
          </ul>
        </div>
        <div>
          <el-input icon="el-icon-search" v-model="keyword" :class="[$style.search]" placeholder="输入文档名称搜索" size="small" @change="onSearch"></el-input>
        </div>
      </div>
      <div :class="[$style.listWrap]">
        <ul :class="[$style.list]" v-infinite-scroll="onLoad" :infinite-scroll-disabled="disabled" :infinite-scroll-immediate="false">
          <inline-input :before-confirm-fn="beforeConfirmFn" :class="[$style.item]" ref="inlineInput">
            <template v-slot:prepend>
              <span class="mr-2"><doc-icon :data="{ type: 'dir' }"></doc-icon></span>
            </template>
          </inline-input>
          <li :class="[$style.item]" v-for="(row, i) in pageData.rows" :key="i" :disabled="row.type !== 'dir'" @click="onSelectDoc(row)">
            <span><doc-icon :data="row"></doc-icon></span>
            <span class="ml-2" v-if="row.type !== 'dir'">{{row.name}}</span>
            <el-link :underline="false" class="ml-2" @click="onSelectDoc(row)" v-else>{{row.name}}</el-link>
          </li>
        </ul>
        <p class="text-center text-secondary" v-if="pageData.loading"><i class="el-icon-loading"></i></p>
      </div>
    </div>
  </div>
  <div slot="footer">
    <div :class="[$style.footer]">
      <el-button size="small" class="px-5" :disabled="!current && !root" @click="onMkDir">新建文件夹</el-button>
      <span>
        <el-button size="small" @click="onCancel" class="px-5">取 消</el-button>
        <el-button size="small" type="primary" @click="onConfirm" :loading="submitting" class="px-5">{{type === 'mv' ? '移 动' : '复 制'}}</el-button>
      </span>
    </div>
  </div>
</el-dialog>
</div>
</template>

<script lang="ts">

import { getUserDocs, getUserRootDocs, mv, cp, getEntRootDocs, getUserRootDoc, getEntRootDoc, mkdir } from '@/api/doc'
import { PageData, PageQueryParams } from '@/config/page'
import { AppModule } from '@/store'
import { Vue, Component, Prop, Emit, Ref } from 'vue-property-decorator'

@Component
export default class DocMvModal extends Vue {
  @Ref() fm!: any

  @Ref() navList!: HTMLElement

  @Ref() inlineInput!: any

  @AppModule.State spaces!: any[]

  @AppModule.State currentSpace!: any

  visible = false

  sources: any[] = []

  type: 'mv' | 'cp' = 'mv'

  resolve: ((value: any) => void) | null = null

  reject: (() => void) | null = null

  submitting = false

  pageData: PageData<any> = null as any

  cache: Map<string, any> = new Map()

  space: any = null

  current: any = null

  keyword = ''

  breadcrumbLength = 0

  root: any = null

  get renderedSpaces () {
    if (this.type === 'cp') return this.spaces
    const source = this.sources && this.sources[0]
    if (!source) return []
    return this.spaces.filter(v => {
      return (v.type === 'user' && v.type === source.ownType) || (v.type !== 'user' && v.type === source.ownType && v.ownId === source.ownId)
    })
  }

  get loader () {
    const vm = this
    return (params: PageQueryParams) => {
      const extra = Object.assign({}, params, { prop: 'modifiedTime', order: 'desc' })
      let p
      if (this.current) p = getUserDocs(extra, this.current?.id)
      else {
        if (this.space?.type === 'user') {
          p = getUserRootDocs(extra)
        } else {
          p = getEntRootDocs(this.space?.ownId, extra)
        }
      }
      return p
    }
  }

  get disabled () {
    return this.pageData.loading || !this.pageData.hasMore
  }

  get paths () {
    const ret = (this.current?.path || '').split('/')
    return ret.map((v: string, i: number) => {
      return {
        path: ret.slice(0, i + 1).join('/'),
        name: i === 0 ? this.space?.name : v,
        last: i === ret.length - 1,
        level: i
      }
    })
  }

  get renderedPaths () {
    const max = Math.max(Math.floor(this.breadcrumbLength / 60), 2)
    if (this.paths.length > max) {
      return [this.paths[0], ...this.paths.slice(-max + 1)]
    } else {
      return this.paths
    }
  }

  beforeConfirmFn (value: string) {
    const s = this.current || this.root
    return mkdir(s.id, value).then(() => {
      this.$message.success('新建文件夹成功')
      this.pageData.reload(true)
    })
  }

  icon (row: any) {
    return row.type === 'user' ? 'docs' : 'ent-docs'
  }

  open (sources: any[], type: 'mv' | 'cp' = 'mv') {
    this.sources = sources || []
    this.type = type
    this.current = null
    this.space = null
    this.onSelectSpace(this.renderedSpaces[0])
    this.cache.clear()
    return new Promise((resolve, reject) => {
      this.resolve = resolve
      this.reject = reject
      this.visible = true
    })
  }

  onSelectSpace (row: any) {
    this.space = row || null
    this.current = null
    this.pageData.load()
    if (this.space) {
      const request = this.space.type === 'user' ? getUserRootDoc() : getEntRootDoc(this.space?.ownId)
      request.then(data => {
        this.root = data || null
      })
    }
  }

  onSelectDoc (row: any) {
    if (row.type !== 'dir') return
    this.current = row || null
    if (this.current) this.cache.set(this.current?.path, this.current)
    this.pageData.load()
  }

  onLoad () {
    this.pageData.loadNext()
  }

  spaceSelectedCls (row: any) {
    return row === this.space ? this.$style.selected : ''
  }

  onSearch () {
    this.pageData.load({ name: this.keyword || undefined })
  }

  onGoto (row: any) {
    if (row.level < 1) {
      this.current = null
    } else {
      this.current = this.cache.get(row.path) || null
    }
    this.pageData.load()
  }

  onMkDir () {
    this.inlineInput.open('新建文件夹').catch(() => {
      // ignore
    })
  }

  onCancel () {
    this.visible = false
    if (this.reject) this.reject()
  }

  onConfirm () {
    if (!this.current && !this.root) {
      this.$message.warning('请指定目标文件夹')
      return
    }
    const target = this.current || this.root
    const isSub = this.sources.some(v => {
      return (target.path + '/').startsWith(v.path + '/')
    })
    if (isSub) {
      this.$message.info('目标文件夹不能是源文档的子文件夹')
      return
    }
    const req = {
      sources: this.sources.map(v => v.id),
      target: target.id
    }
    const request = this.type === 'mv' ? mv(req) : cp(req)
    this.submitting = true
    request.then(data => {
      this.visible = false
      if (this.resolve) this.resolve(data)
    }).finally(() => {
      this.submitting = false
    })
  }

  created () {
    this.pageData = new PageData(this.loader)
  }

  updated () {
    if (this.navList) this.breadcrumbLength = this.navList.offsetWidth
  }

  $style!: any
}
</script>

<style lang="scss" module>
@import "~@/styles/vars.scss";

.container {

}

.body {
  display: flex;
  height: calc(70vh - 160px);
}

.menu {
  width: 20%;
  flex: 1 1 auto;
  border-right: 1px solid $border-split-color;
  padding-right: 20px;
}

.listWrap {
  height: calc(100% - 32px);
}

.list {
  list-style: none;
  margin: 0;
  padding: 0;
  height: 100%;
  overflow: auto;
}

.menuText {
  white-space: nowrap;
  text-overflow: ellipsis;
  overflow: hidden;
}

.item {
  height: 42px;
  display: flex;
  align-items: center;
  padding: 0 12px;

  &:hover {
    background-color: $bg-head-color;
    cursor: pointer;
  }

  &.selected {
    background-color: $bg-body-color;
  }

  &[disabled] {
    cursor: not-allowed;
    opacity: .6;
  }
}

.content {
  flex: 1 1 auto;
  width: 80%;
  padding-left: 12px;
}

.breadcrumb {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.navListWrap {
  flex: 1 1 auto;
  margin-right: 12px;
}

.navList {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  width: 0;
  min-width: 100%;
}

.navItem {
  align-items: center;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  position: relative;
  padding-right: 16px;
  min-width: 60px;
}

.navSep {
  position: absolute;
  right: 2px;
  top: 50%;
  transform: translateY(-50%);
}

.navItemLink {

  &:hover {
    color: $color-primary;
    cursor: pointer;
  }
}

.search {
  width: 200px;
}

.footer {
  display: flex;
  justify-content: space-between;
}

</style>
